<?php

/**
 * This file contains the web displaying function for block tree type class
 *
 * @author Isuru Madushanka Weerarathna
 * @version  $Id: coursetree.php,v 1.0.0.1 2010/12/28 11:23:55
 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
 * @package lib
 */
 
 /// Import libraries

require_once($CFG->libdir.'/weblib.php');
require_once($CFG->libdir.'/datalib.php');
require_once($CFG->dirroot . '/course/lib.php');


/// Constants...

/**
 * Stores icon file names that used only in Tree style blocks to show the expanded/collapsed state of the tree.
 */
define('COLLAPSED_ICON' , 'arrow_collapsed.gif');
define('EXPANDED_ICON' , 'arrow_expanded.gif');

/**
 * Stores the number of dates to have the cookie before expiration since last access.
 */
define('COOKIE_EXPIRE_DATE', 31);

/**
 * Stores the constants for counting course attributes.
 */
define('CALCULATE_COMPLETED_COURSES', 1);       // counts completed courses
define('CALCULATE_NONCOMPLETED_COURSES', 0);    // counts currently on-going courses.
define('CALCULATE_ALL_COURSES', -1);            // counts all courses
define('CALCULATE_UPDATED_COURSES', 2);         // counts recently updates courses since users last login.

///Functions are stating from here...

/*
 * Author:  Isuru Madushanka
 *
 * Returns an integer that represents how many number of activities have been scheduled
 * since current user's last log-in. This function trawls through the logs looking for
 * anything new since the user's last login.
 * 
 * param $course course to be searched for recent activities
 */
function get_number_of_recent_activities($course) {
    $count = 0;     // variable for holding number of recent activities
    global $CFG, $USER, $SESSION;

    $context = get_context_instance(CONTEXT_COURSE, $course->id);

    $viewfullnames = has_capability('moodle/site:viewfullnames', $context);

    $timestart = round(time() - COURSE_MAX_RECENT_PERIOD, -2); // better db caching for guests - 100 seconds

    if (!has_capability('moodle/legacy:guest', $context, NULL, false)) {
        if (!empty($USER->lastcourseaccess[$course->id])) {
            if ($USER->lastcourseaccess[$course->id] > $timestart) {
                $timestart = $USER->lastcourseaccess[$course->id];
            }
        }
    }

    /// have there been any modifications to the course structure?
    $modinfo =& get_fast_modinfo($course);

    $changelist = array();

    $logs = get_records_select('log', "time > $timestart AND course = $course->id AND
                                       module = 'course' AND
                                       (action = 'add mod' OR action = 'update mod' OR action = 'delete mod')",
                               "id ASC");

    if ($logs) {
        $actions  = array('add mod', 'update mod', 'delete mod');
        $newgones = array(); // added and later deleted items
        foreach ($logs as $key => $log) {
            if (!in_array($log->action, $actions)) {
                continue;
            }
            
            $info = split(' ', $log->info);

            if ($info[0] == 'label') {     // Labels are ignored in recent activity
                continue;
            }

            if (count($info) != 2) {
                debugging("Incorrect log entry info: id = ".$log->id, DEBUG_DEVELOPER);
                continue;
            }

            $count++;
            
        }
    }
    
    return $count;

}

function get_print_recent_activity($course, &$count) {
    global $CFG, $USER, $SESSION;

    $res = '';
    $count = 0;
    $updatedcrs = '';
    $deletedcrs = '';
    $addedcrs = '';

    $context = get_context_instance(CONTEXT_COURSE, $course->id);

    $viewfullnames = has_capability('moodle/site:viewfullnames', $context);

    $timestart = round(time() - COURSE_MAX_RECENT_PERIOD, -2); // better db caching for guests - 100 seconds

    if (!has_capability('moodle/legacy:guest', $context, NULL, false)) {
        if (!empty($USER->lastcourseaccess[$course->id])) {
            if ($USER->lastcourseaccess[$course->id] > $timestart) {
                $timestart = $USER->lastcourseaccess[$course->id];
            }
        }
    }
    $content = false;

/// Firstly, have there been any new enrolments?

    $users = get_recent_enrolments($course->id, $timestart);

    //Accessibility: new users now appear in an <OL> list.
    if ($users) {
        $res .= '<div><table><thead><td>New Users</td></thead>';
        //print_headline(get_string("newusers").':', 3);
        $content = true;
        //echo "<ol class=\"list\">\n";
        foreach ($users as $user) {
            $count++;
            $fullname = fullname($user, $viewfullnames);
            //echo '<li class="name"><a href="'."$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a></li>";
            $res .= "<tr><td><a href=\"$CFG->wwwroot/user/view.php?id=$user->id&amp;course=$course->id\">$fullname</a></td></tr>";
        }

        echo "</table></div>";
    }

/// Next, have there been any modifications to the course structure?

    $modinfo =& get_fast_modinfo($course);

    $changelist = array();

    $logs = get_records_select('log', "time > $timestart AND course = $course->id AND
                                       module = 'course' AND
                                       (action = 'add mod' OR action = 'update mod' OR action = 'delete mod')",
                               "id ASC");

    if ($logs) {
        $actions  = array('add mod', 'update mod', 'delete mod');
        $newgones = array(); // added and later deleted items
        foreach ($logs as $key => $log) {
            if (!in_array($log->action, $actions)) {
                continue;
            }
            $info = split(' ', $log->info);

            if ($info[0] == 'label') {     // Labels are ignored in recent activity
                continue;
            }

            if (count($info) != 2) {
                debugging("Incorrect log entry info: id = ".$log->id, DEBUG_DEVELOPER);
                continue;
            }

            $modname    = $info[0];
            $instanceid = $info[1];

            if ($log->action == 'delete mod') {
                // unfortunately we do not know if the mod was visible
                if (!array_key_exists($log->info, $newgones)) {
                    $strdeleted = get_string('deletedactivity', 'moodle', get_string('modulename', $modname));
                    $changelist[$log->info] = array ('operation' => 'delete', 'text' => $strdeleted);
                }
            } else {
                if (!isset($modinfo->instances[$modname][$instanceid])) {
                    if ($log->action == 'add mod') {
                        // do not display added and later deleted activities
                        $newgones[$log->info] = true;
                    }
                    continue;
                }
                $cm = $modinfo->instances[$modname][$instanceid];
                if (!$cm->uservisible) {
                    continue;
                }

                if ($log->action == 'add mod') {
                    $stradded = get_string('added', 'moodle', get_string('modulename', $modname));
                    $changelist[$log->info] = array('operation' => 'add', 'text' => "<a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id={$cm->id}\">".format_string($cm->name, true)."</a>");

                } else if ($log->action == 'update mod' and empty($changelist[$log->info])) {
                    $strupdated = get_string('updated', 'moodle', get_string('modulename', $modname));
                    $changelist[$log->info] = array('operation' => 'update', 'text' => "<a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id={$cm->id}\">".format_string($cm->name, true)."</a>");
                }
            }
        }
    }

    if (!empty($changelist)) {
        //print_headline(get_string('courseupdates').':', 3);
        $updatedcrs = '<div><table><thead><td><b>Updated:</b></td></thead>';
        $addedcrs = '<div><table><thead><td><b>Added:</b></td></thead>';
        $deletedcrs = '<div><table><thead><td><b>Deleted:</b></td></thead>';
        $indcount = array('delete'=>0, 'add'=>0, 'update'=>0);

        $content = true;
        foreach ($changelist as $changeinfo => $change) {
            $indcount[$change['operation']]++;
            if ($change['operation']=='update') {
                $updatedcrs .= '<tr><td>'.$change['text'].'</td></tr>';
                $count++;
            } else if ($change['operation']=='add') {
                $addedcrs .= '<tr><td>'.$change['text'].'</td></tr>';
                $count++;
            } else if ($change['operation']=='delete') {
                $deletedcrs .= '<tr><td>'.$change['text'].'</td></tr>';
                $count++;
            }
        }

        if ($indcount['add'] > 0) {
            $res .= '<br/>'.$addedcrs.'</table></div>';
        }
        if ($indcount['update'] > 0) {
            $res .= '<br/>'.$updatedcrs.'</table></div>';
        }
        if ($indcount['delete'] > 0) {
            $res .= '<br/>'.$deletedcrs.'</table></div>';
        }
    }

    if (! $content) {
        return '';
    }
    return $res;
}




/**
 * Modified By: U.Isuru Madushanka Weerarathna
 * Inherited from: get_my_courses(...) function in datalib.php file that is located in lib directory.
 *
 * This function is the slightly modified function for get_my_courses(..) function is datalib.php!
 * To calculate the end date of a course, I've fetched the 'numsections' attribute with other course
 * details. 'numsections' includes duration of the course by weeks.
 *
 * Convenience function - lists courses that a user has access to view.
 *
 * @uses $CFG,$USER
 * @param int $userid The user of interest
 * @param string $sort the sortorder in the course table
 * @param array $fields - names of _additional_ fields to return (also accepts a string)
 * @param bool $doanything True if using the doanything flag
 * @param int $limit Maximum number of records to return, or 0 for unlimited
 * @return array {@link $COURSE} of course objects
 */
function get_my_courses_forcoursetree($userid, $sort='visible DESC,sortorder ASC', $fields=NULL, $doanything=false,$limit=0) {

    global $CFG,$USER;

    // Guest's do not have any courses
    $sitecontext = get_context_instance(CONTEXT_SYSTEM);
    if (has_capability('moodle/legacy:guest',$sitecontext,$userid,false)) {
        return(array());
    }

    $basefields = array('id', 'category', 'sortorder',
                        'shortname', 'fullname', 'idnumber',
                        'teacher', 'teachers', 'student', 'students',
                        'guest', 'startdate', 'visible',
                        'newsitems',  'cost', 'enrol',
                        'groupmode', 'groupmodeforce', 'numsections');

    if (!is_null($fields) && is_string($fields)) {
        if (empty($fields)) {
            $fields = $basefields;
        } else {
            // turn the fields from a string to an array that
            // get_user_courses_bycap() will like...
            $fields = explode(',',$fields);
            $fields = array_map('trim', $fields);
            $fields = array_unique(array_merge($basefields, $fields));
        }
    } elseif (is_array($fields)) {
        $fields = array_unique(array_merge($basefields, $fields));
    } else {
        $fields = $basefields;
    }

    $orderby = '';
    $sort    = trim($sort);
    if (!empty($sort)) {
        $rawsorts = explode(',', $sort);
        $sorts = array();
        foreach ($rawsorts as $rawsort) {
            $rawsort = trim($rawsort);
            if (strpos($rawsort, 'c.') === 0) {
                $rawsort = substr($rawsort, 2);
            }
            $sorts[] = trim($rawsort);
        }
        $sort = 'c.'.implode(',c.', $sorts);
        $orderby = "ORDER BY $sort";
    }

    //
    // Logged-in user - Check cached courses
    //
    // NOTE! it's a _string_ because
    // - it's all we'll ever use
    // - it serialises much more compact than an array
    //   this a big concern here - cost of serialise
    //   and unserialise gets huge as the session grows
    //
    // If the courses are too many - it won't be set
    // for large numbers of courses, caching in the session
    // has marginal benefits (costs too much, not
    // worthwhile...) and we may hit SQL parser limits
    // because we use IN()
    //
    if ($userid === $USER->id) {
        if (isset($USER->loginascontext)
            && $USER->loginascontext->contextlevel == CONTEXT_COURSE) {
            // list _only_ this course
            // anything else is asking for trouble...
            $courseids = $USER->loginascontext->instanceid;
        } elseif (isset($USER->mycourses)
                  && is_string($USER->mycourses)) {
            if ($USER->mycourses === '') {
                // empty str means: user has no courses
                // ... so do the easy thing...
                return array();
            } else {
                $courseids = $USER->mycourses;
            }
        }
        if (isset($courseids)) {
            // The data massaging here MUST be kept in sync with
            // get_user_courses_bycap() so we return
            // the same...
            // (but here we don't need to check has_cap)
            $coursefields = 'c.' .join(',c.', $fields);
            $sql = "SELECT $coursefields,
                           ctx.id AS ctxid, ctx.path AS ctxpath,
                           ctx.depth as ctxdepth, ctx.contextlevel AS ctxlevel,
                           cc.path AS categorypath
                    FROM {$CFG->prefix}course c
                    JOIN {$CFG->prefix}course_categories cc
                      ON c.category=cc.id
                    JOIN {$CFG->prefix}context ctx
                      ON (c.id=ctx.instanceid AND ctx.contextlevel=".CONTEXT_COURSE.")
                    WHERE c.id IN ($courseids)
                    $orderby";
            $rs = get_recordset_sql($sql);
            $courses = array();
            $cc = 0; // keep count
            while ($c = rs_fetch_next_record($rs)) {
                // build the context obj
                $c = make_context_subobj($c);

                if ($limit > 0 && $cc >= $limit) {
                    break;
                }
                
                $courses[$c->id] = $c;
                $cc++;
            }
            rs_close($rs);
            return $courses;
        }
    }

    // Non-cached - get accessinfo
    if ($userid === $USER->id && isset($USER->access)) {
        $accessinfo = $USER->access;
    } else {
        $accessinfo = get_user_access_sitewide($userid);
    }


    $courses = get_user_courses_bycap($userid, 'moodle/course:view', $accessinfo,
                                      $doanything, $sort, $fields,
                                      $limit);

    $cats = NULL;
    // If we have to walk category visibility
    // to eval course visibility, get the categories
    if (empty($CFG->allowvisiblecoursesinhiddencategories)) {
        $sql = "SELECT cc.id, cc.path, cc.visible,
                       ctx.id AS ctxid, ctx.path AS ctxpath,
                       ctx.depth as ctxdepth, ctx.contextlevel AS ctxlevel
                 FROM {$CFG->prefix}course_categories cc
                 JOIN {$CFG->prefix}context ctx ON (cc.id = ctx.instanceid)
                WHERE ctx.contextlevel = ".CONTEXT_COURSECAT."
             ORDER BY cc.id";
        $rs = get_recordset_sql($sql);

        // Using a temporary array instead of $cats here, to avoid a "true" result when isnull($cats) further down
        $categories = array();
        while ($course_cat = rs_fetch_next_record($rs)) {
            // build the context obj
            $course_cat = make_context_subobj($course_cat);
            $categories[$course_cat->id] = $course_cat;
        }
        rs_close($rs);

        if (!empty($categories)) {
            $cats = $categories;
        }

        unset($course_cat);
    }
    //
    // Strangely, get_my_courses() is expected to return the
    // array keyed on id, which messes up the sorting
    // So do that, and also cache the ids in the session if appropriate
    //
    $kcourses = array();
    $courses_count = count($courses);
    $cacheids = NULL;
    $vcatpaths = array();
    if ($userid === $USER->id && $courses_count < 500) {
        $cacheids = array();
    }
    for ($n=0; $n<$courses_count; $n++) {

        //
        // Check whether $USER (not $userid) can _actually_ see them
        // Easy if $CFG->allowvisiblecoursesinhiddencategories
        // is set, and we don't have to care about categories.
        // Lots of work otherwise... (all in mem though!)
        //
        $cansee = false;
        if (is_null($cats)) { // easy rules!
            if ($courses[$n]->visible == true) {
                $cansee = true;
            } elseif (has_capability('moodle/course:viewhiddencourses',
                                     $courses[$n]->context, $USER->id)) {
                $cansee = true;
            }
        } else {
            //
            // Is the cat visible?
            // we have to assume it _is_ visible
            // so we can shortcut when we find a hidden one
            //
            $viscat = true;
            $cpath = $courses[$n]->categorypath;
            if (isset($vcatpaths[$cpath])) {
                $viscat = $vcatpaths[$cpath];
            } else {
                $cpath = substr($cpath,1); // kill leading slash
                $cpath = explode('/',$cpath);
                $ccct  = count($cpath);
                for ($m=0;$m<$ccct;$m++) {
                    $ccid = $cpath[$m];
                    if ($cats[$ccid]->visible==false) {
                        $viscat = false;
                        break;
                    }
                }
                $vcatpaths[$courses[$n]->categorypath] = $viscat;
            }

            //
            // Perhaps it's actually visible to $USER
            // check moodle/category:viewhiddencategories
            //
            // The name isn't obvious, but the description says
            // "See hidden categories" so the user shall see...
            // But also check if the allowvisiblecoursesinhiddencategories setting is true, and check for course visibility
            if ($viscat === false) {
                $catctx = $cats[$courses[$n]->category]->context;
                if (has_capability('moodle/category:viewhiddencategories', $catctx, $USER->id)) {
                    $vcatpaths[$courses[$n]->categorypath] = true;
                    $viscat = true;
                } elseif ($CFG->allowvisiblecoursesinhiddencategories && $courses[$n]->visible == true) {
                    $viscat = true;
                }
            }

            //
            // Decision matrix
            //
            if ($viscat === true) {
                if ($courses[$n]->visible == true) {
                    $cansee = true;
                } elseif (has_capability('moodle/course:viewhiddencourses',
                                        $courses[$n]->context, $USER->id)) {
                    $cansee = true;
                }
            }
        }
        if ($cansee === true) {
            $kcourses[$courses[$n]->id] = $courses[$n];
            if (is_array($cacheids)) {
                $cacheids[] = $courses[$n]->id;
            }
        }
    }
    if (is_array($cacheids)) {
        // Only happens
        // - for the logged in user
        // - below the threshold (500)
        // empty string is _valid_
        $USER->mycourses = join(',',$cacheids);
    } elseif ($userid === $USER->id && isset($USER->mycourses)) {
        // cheap sanity check
        unset($USER->mycourses);
    }

    return $kcourses;
}




/**
 * Prints a nice tree side block with an optional header.  The content can only be tree style!.
 *
 * @param  string $heading Block $title embedded in HTML tags and bahaviour of block when clicking plus and minus sign.
 * @param  string $content In this tree type structure it is NULL. (Not required!)
 * @param  array $sub_blocks all the categorized tree levels (Depth 0)
 * @param  array $attributes important parameters for the blocks, id, classtype etc...
 * @param  string $title Plain text title, as embedded in the $heading.
 */
function print_side_tree_main_block($heading='', $content='', $sub_blocks=NULL, $all_headings=NULL, $attributes = array(), $title='') {
    global $THEME, $CFG, $USER;
    
    //Accessibility: skip block link, with title-text (or $block_id) to differentiate links.
    $skip_text = get_string('skipa', 'access', strip_tags($title));
    $skip_link = '<a href="#sb-'.$block_id.'" class="skip-block">'.$skip_text.'</a>';
    $skip_dest = '<span id="sb-'.$block_id.'" class="skip-block-to"></span>';

    $strip_title = strip_tags($title);
    if (! empty($strip_title)) {
        echo $skip_link;
    }
    //ELSE: a single link on a page "Skip block 4" is too confusing - ignore.

    // prints the title bar of the block with it's behaviours.
    print_tree_block_start($heading, $attributes);

    if ($content) {         // if the content has something to say...

        // print just the content. don't fancy!
        echo $content;

        if ($footer) {      // if a footer exist, print the footer
            echo '<div class="footer">'. $footer .'</div>';
        }

        print_side_block_end($attributes, $title);
        echo $skip_dest;

    } else {

        /* important level of printing tree structure. */

        if ($sub_blocks) {      // are there any blocks to be printed???

            /* stores an ID for each level of the tree. each tree node level must be unique to identify
               it's beahiours such as collapsing and expanding. */
            $current_block = 0;
            $to_collapse = '';

            if ($CFG->block_course_list_showsettings) {
                $cookval = $_COOKIE['show_completed_'.$USER->username];
                //echo '<font size=1></font>';
                //echo '<div class="footer"><b><u>Personal settings:</u></b></div>';
                echo '<div align="LEFT">';
                echo '<table><tr><td>';
                echo '<input type="checkbox" id="showcompleted"';
                if ($cookval == 1)
                    echo ' value="1" checked="checked"';
                else
                    echo ' value="0"';

                echo ' onClick="setshow()" ><font size="1">';
                echo get_string('showcompletedcoursecheckbox', 'block_course_treelist');
                echo '&nbsp;&nbsp</font></input>';
                echo '</td><td align="left"><font size=1>';
                echo '<a href="#" onClick="collapseall();return false;">';
                echo '<img src='.$CFG->pixpath.'/i/collapseall.gif'.' />'.'&nbsp;';
                echo get_string('collapseallbutton', 'block_course_treelist').'</a><br>';
                echo '<a href="#" onClick="expandall();return false;">';
                echo '<img src='.$CFG->pixpath.'/i/expandall.gif'.' />'.'&nbsp;';
                echo get_string('expandallbutton', 'block_course_treelist').'</a><br>';
                echo '</font></td></tr></table>';
                echo '</div>';
                
                echo '<div class="footer"></div>';
            }

            // introducing content type is a tree type. Abstracted from 'admintree'.
            echo '<div class="admintree">';

            foreach ($sub_blocks as $block) {   // iterating through each block (that is tree node)...

                $completed_courses = get_total_courses($block, CALCULATE_COMPLETED_COURSES);
                $noncompleted_courses = get_total_courses($block, CALCULATE_NONCOMPLETED_COURSES);
                $all_courses = get_total_courses($block, CALCULATE_ALL_COURSES);
                $updated_courses = get_total_courses($block, CALCULATE_UPDATED_COURSES);

                
                $current_block++;       // increase the current block ID by one.


                // check whether all courses in the current node has completed. If
                // completed then node will not display.
                if ($CFG->block_course_list_automatichidenode) {
                    if ($cookval == 0 && ($all_courses == $completed_courses))
                        continue;
                }

                // prints a top level node to include all the courses for this category.
                echo '
                <div class="depth0">
                    <a href="#" onclick="menu_toggle(\''.$current_block.'\');return false">
                    <span id="vh_div'.$current_block.'indicator">
                    <img src="'.$CFG->pixpath.'/i/'.COLLAPSED_ICON.'" alt="-" />
                    </span><u><b> '.$block->title.'</b></u></a>
                </div>'."\n".'<div id="vh_div'.$current_block.'">';

                /* checking each and every item under current root node */
                $current_item = 0;

                // check for all courses in current node are completed or not. If true, then
                // the node will be collapsed at initially.
                $expand_node_state = $_COOKIE['blockcourselist_node'.$current_block.'_'.$USER->username];
                if ($all_courses == $completed_courses && $expand_node_state == 0) {
                    $to_collapse = $to_collapse . ($to_collapse == '' ? '' : ','). $current_block;
                } else if ($expand_node_state == 0) {
                    $to_collapse = $to_collapse . ($to_collapse == '' ? '' : ','). $current_block;
                }


                while ( ($completed_courses > 0 || $noncompleted_courses > 0)  ) {
                  if ( ($noncompleted_courses <= 0 && $completed_courses <= 0) ) {
                        break;
                  }
                  
                  $current_item = 0;

                  foreach ($block->items as $key => $string) {
                    
                    if ($updated_courses > 0) {
                        
                        if ($block->recent_activites[$current_item] > 0 && $block->flags[$current_item] > 0) {
                                $updated_courses--;
                                
                                if ($block->visibility[$current_item] && $block->flags[$current_item] > 0) {
                                    $noncompleted_courses--;
                                }
                                if ((!$block->visibility[$current_item]) && $block->flags[$current_item] > 0) {
                                    $completed_courses--;
                                }
                                
                                $block->flags[$current_item] = 0;
                                
                        } else {
                                $current_item++;
                                continue;
                        }
                        
                    } else {
                        
                        if ($noncompleted_courses > 0) {
                            if ($block->visibility[$current_item] && $block->flags[$current_item] > 0) {
                                $noncompleted_courses--;
                                $block->flags[$current_item] = 0;
                            } else {
                                $current_item++;
                                continue;
                            }
                        } else if ($noncompleted_courses <= 0) {
                            if ($completed_courses <= 0) break;

                            if ((!$block->visibility[$current_item]) && $block->flags[$current_item] > 0) {
                                $completed_courses--;
                                $block->flags[$current_item] = 0;
                            } else {
                                $current_item++;
                                continue;
                            }
                        }
                        
                    }
                    
                    if ($cookval == 0 && $CFG->block_course_list_showsettings && !$block->visibility[$current_item])
                        continue;

                    // creating a children node.
                    echo '<div class="depth1">';

                    // if item has a icon to display, then show it.
                    if ($block->icons) {
                        echo $block->icons[$key]."\n";
                    }

                    // indicates end of children node.
                    echo $string ."\n</div>\n";

                    $current_item++;

                  }  // end of each item node

                }

                // close the depth2 division and make a space between this and next level.
                echo "</div>\n";

                if ($block->footer) {
                    echo '<div class="footer">'. $block->footer .'</div>';
                }

                if (!empty($THEME->customcorners)) {
                    echo '</div></div></div><div class="bb"><div>&nbsp;</div></div></div>';
                }

            }

        }

        // prints the end of block with JavaScripts which needs to control the behaviour of tree structure.
        if ($CFG->block_course_list_automaticcollapse == '1')
            print_side_tree_block_end($attributes, $title, true, $current_block, $to_collapse);
        else
            print_side_tree_block_end($attributes, $title, true, $current_block);

        echo $skip_dest;

    }

}

/**
 * Calculates the number of types of courses in given node.
 * Type of courses can only be completed or non-completed.
 *
 * @Author Isuru Madushanka
 * @param  array $block node which has to be scanned.
 * @param  integer $completed Type of course. Updated_courses = 2, Completed = 1, non-completed = 0, and
 *                             if value is -1 then returns count of all courses in the node.
 */
function get_total_courses($block, $completed = 1) {
    $current_item = 0;
    $total_courses = 0;

    foreach ($block->items as $key => $string) {

        if ($completed == CALCULATE_COMPLETED_COURSES) {
            if (!$block->visibility[$current_item]) {
                $total_courses++;
            }
        } else if ($completed == CALCULATE_NONCOMPLETED_COURSES) {
            if ($block->visibility[$current_item]) {
                $total_courses++;
            }
        } else if ($completed == CALCULATE_UPDATED_COURSES) {
            if ($block->recent_activites[$current_item] > 0) {
                $total_courses++;
            }       
        } else if ($completed == CALCULATE_ALL_COURSES) {
            $total_courses++;
        } 

        $current_item++;
    }

    return $total_courses;
}

/**
 * Starts a nice side block with an optional header.
 *
 * @param string $heading ?
 * @param array $attributes ?
 * @todo Finish documenting this function
 */
function print_tree_block_start($heading='', $attributes = array()) {

    global $CFG, $THEME;

    // If there are no special attributes, give a default CSS class
    if (empty($attributes) || !is_array($attributes)) {
        $attributes = array('class' => 'sideblock');

    } else if(!isset($attributes['class'])) {
        $attributes['class'] = 'sideblock';

    } else if(!strpos($attributes['class'], 'sideblock')) {
        $attributes['class'] .= ' sideblock';
    }

    // OK, the class is surely there and in addition to anything
    // else, it's tagged as a sideblock

    /*

    // IE misery: if I do it this way, blocks which start hidden cannot be "unhidden"

    // If there is a cookie to hide this thing, start it hidden
    if (!empty($attributes['id']) && isset($_COOKIE['hide:'.$attributes['id']])) {
        $attributes['class'] = 'hidden '.$attributes['class'];
    }
    */

    $attrtext = '';
    foreach ($attributes as $attr => $val) {
        $attrtext .= ' '.$attr.'="'.$val.'"';
    }

    echo '<div '.$attrtext.'>';

    if (!empty($THEME->customcorners)) {
        echo '<div class="wrap">'."\n";
    }
    if ($heading) {
        //Accessibility:  H2 more appropriate in moodleblock.class.php: _title_html.
        echo '<div class="header">';
        if (!empty($THEME->customcorners)) {
            echo '<div class="bt"><div>&nbsp;</div></div>';
            echo '<div class="i1"><div class="i2">';
            echo '<div class="i3">';
        }
        echo $heading;
        if (!empty($THEME->customcorners)) {
            echo '</div></div></div>';
        }
        echo '</div>';
    } else {
        if (!empty($THEME->customcorners)) {
            echo '<div class="bt"><div>&nbsp;</div></div>';
        }
    }

    if (!empty($THEME->customcorners)) {
        echo '<div class="i1"><div class="i2">';
        echo '<div class="i3">';
    }
    echo '<div class="content">';

}

/**
 * Prints the end of the tree block structure. Since, tree block requires different
 * type of content type (specially, javascripts) different methods has to be used.
 *
 * @Author Isuru Madushanka
 * @param  array $attributes important parameters identifying whoch block type is processing
 * @param  string $title Plain text title, as footer
 */
function print_side_tree_block_end($attributes = array(), $title='',$is_subblock = false, $no_of_div = 0, $collapse_fields = '') {
    global $CFG, $THEME, $USER;

    echo '</div>';
    if (!empty($THEME->customcorners)) {
        echo '</div></div></div><div class="bb"><div>&nbsp;</div></div></div>';
    }
    echo '</div>';

    $strshow = addslashes_js(get_string('showblocka', 'access', strip_tags($title)));
    $strhide = addslashes_js(get_string('hideblocka', 'access', strip_tags($title)));

    // IE workaround: if I do it THIS way, it works! WTF?
    if (!empty($CFG->allowuserblockhiding) && isset($attributes['id'])) {
        if (!$is_subblock) {
            echo '<script type="text/javascript">'."\n//<![CDATA[\n".'elementCookieHide("'.$attributes['id'].
                '","'.$strshow.'","'.$strhide."\");\n//]]>\n".'</script>';
        } else {
            /// prints the Javascript functions which are needed for controlling behaviour of tree when user clicked on an item.
            echo '<script type="text/javascript">'."\n//<![CDATA[\n
                        var vh_numdivs = ".$no_of_div.";
                        var parkplatz  = new Array();
                        for (var i=1; i<=vh_numdivs; i++) {
                            parkplatz[i] = null;
                        }

                        function menu_toggle(i) {
                            i = parseInt(i);
                            if (parkplatz[i] === null) {
                                collapse(i);
                            } else {
                                expand(i);
                            }
                        }

                        function setshow() {
                            var obj = document.getElementById(\"showcompleted\");
                            if (obj==null) return;


                            var expDate = new Date();
                            expDate.setDate(expDate.getDate() + ".COOKIE_EXPIRE_DATE.");
                            var expires = \"; expires=\" + expDate.toUTCString();

                            if (obj.checked) document.cookie = \"show_completed_$USER->username=1\" + expires;
                            else document.cookie = \"show_completed_$USER->username=0\" + expires;

                            document.location.reload();
                        }

                        function collapse(i) {
                            if (parkplatz[i] !== null) {
                                return;
                            }
                            var obj = document.getElementById(\"vh_div\"+String(i));
                            if (obj === null) {
                                return;
                            }
                            var nothing = document.createElement(\"span\");
                            nothing.setAttribute(\"id\", \"vh_div\"+String(i));
                            parkplatz[i] = obj;
                            obj.parentNode.replaceChild(nothing, obj);
                            var icon = document.getElementById(\"vh_div\"+String(i)+\"indicator\");
                            icon.innerHTML = \"<img src=\\\"".$CFG->pixpath."/i/".EXPANDED_ICON."\\\" alt=\\\"+\\\" />\";

                            
                            var expDate = new Date();
                            expDate.setDate(expDate.getDate() + 100);
                            var expires = \"; expires=\" + expDate.toUTCString();
                            document.cookie = \"blockcourselist_node\"+i+\"_$USER->username=0\" + expires;
                            
                        }

                        function expand(i) {
                            if (parkplatz[i] === null) {
                                return;
                            }
                            var nothing = document.getElementById(\"vh_div\"+String(i));
                            var obj = parkplatz[i];
                            parkplatz[i] = null;
                            nothing.parentNode.replaceChild(obj, nothing);
                            var icon = document.getElementById(\"vh_div\"+String(i)+\"indicator\");
                            icon.innerHTML = \"<img src=\\\"".$CFG->pixpath."/i/".COLLAPSED_ICON."\\\" alt=\\\"-\\\" />\";

                            var expDate = new Date();
                            expDate.setDate(expDate.getDate() + 100);
                            var expires = \"; expires=\" + expDate.toUTCString();
                            document.cookie = \"blockcourselist_node\"+i+\"_$USER->username=1\" + expires;
                            
                        }

                        function expandall() {
                            for (i=1; i<=vh_numdivs; i++) {
                                expand(i);
                            }
                        }

                        function collapseall() {
                            for (var i=vh_numdivs; i>0; i--) {
                                collapse(i);
                            }
                        }";

            // collapse indicated nodes bacause they all are filled with completed subjects.
            if (strlen($collapse_fields) > 0) {
                $col_array = explode(',', $collapse_fields);

                foreach ($col_array as $collapse_index)
                    echo 'collapse(' . $collapse_index . ');';
            }

            echo "//collapseall();\n//]]>\n".'</script>';

        }

    }

}

/**
 * Sets the ending date of the course
 *
 *  Calculate the course complete time.
 *  Adds number of weeks to the starting date of the course.
 * @Author  Isuru Madushanka
 *
 */
function set_course_endtime($record) {

    // calculates the number of days that course is continuing...
    $totaldays = $record->numsections * 7;
    
    // gets the course starting date
    $tmpdate = getdate($record->startdate);

    // format the starting date to a string. e.g. 2008-04-18
    $date = $tmpdate['year'] .'-'. $tmpdate['mon'] . '-' . $tmpdate['mday'];

    // gets total number of weeks which sucject is scheduled.
    $weeks = $record->numsections;

    // iterating through week by week.
    for ($i = 0; $i < $weeks; ++$i) {
        list($year, $month, $day) = explode('-', $date);
        $time = mktime(0, 0, 0, $month, $day, $year);

        // adds one week for modified time
        $time = strtotime('+1 week', $time);

        // formats the date in readable manner
        $date = date('Y-m-d', $time);
    }

    // sets the end date as calculated date
    $record->enddate = $date;

    $expire_date = strtotime($date);
    
    // gets today date
    $today_date = getdate();

    // format the starting date to a string. e.g. 2008-04-18
    $curr_date = strtotime($today_date['year'].'-'.$today_date['mon'].'-'.$today_date['mday']);
    
    // sets current course record as not expired.
    $record->is_expired = false;

    if ($expire_date < $curr_date)  // if the course end date is already been passes, set course record as expired.
        $record->is_expired = true;



}


/*
 * @Added By    Isuru Madushanka
 * Following two functions are more general function for printing web content of
 * a tree block class.
 */

/**
 * Prints a nice tree side block with an optional header.  The content can only be tree style!.
 *
 * @param  string $heading Block $title embedded in HTML tags and bahaviour of block when clicking plus and minus sign.
 * @param  string $content In this tree type structure it is NULL. (Not required!)
 * @param  array $sub_blocks all the categorized tree levels (Depth 0)
 * @param  array $attributes important parameters for the blocks, id, classtype etc...
 * @param  string $title Plain text title, as embedded in the $heading.
 */
function print_tree_block($heading='', $content='', $sub_blocks=NULL, $all_headings=NULL, $attributes = array(), $title='') {
    global $THEME, $CFG, $USER;

    //Accessibility: skip block link, with title-text (or $block_id) to differentiate links.
    $skip_text = get_string('skipa', 'access', strip_tags($title));
    $skip_link = '<a href="#sb-'.$block_id.'" class="skip-block">'.$skip_text.'</a>';
    $skip_dest = '<span id="sb-'.$block_id.'" class="skip-block-to"></span>';

    $strip_title = strip_tags($title);
    if (! empty($strip_title)) {
        echo $skip_link;
    }
    //ELSE: a single link on a page "Skip block 4" is too confusing - ignore.

    // prints the title bar of the block with it's behaviours.
    print_side_block_start($heading, $attributes);

    if ($content) {         // if the content has something to say...

        // print just the content. don't fancy!
        echo $content;

        if ($footer) {      // if a footer exist, print the footer
            echo '<div class="footer">'. $footer .'</div>';
        }

        print_side_block_end($attributes, $title);
        echo $skip_dest;

    } else {

        /* important level of printing tree structure. */

        if ($sub_blocks) {      // are there any blocks to be printed???

            /* stores an ID for each level of the tree. each tree node level must be unique to identify
               it's beahiours such as collapsing and expanding. */
            $current_block = 0;
            $to_collapse = '';

            // introducing content type is a tree type. Abstracted from 'admintree'.
            echo '<div class="admintree">';

            foreach ($sub_blocks as $block) {   // iterating through each block (that is tree node)...

                $current_block++;       // increase the current block ID by one.

                // prints a top level node to include all the courses for this category.
                echo '
                <div class="depth0">
                    <a href="#" onclick="menu_toggle(\''.$current_block.'\');return false">
                    <span id="vh_div'.$current_block.'indicator">
                    <img src="'.$CFG->pixpath.'/i/'.COLLAPSED_ICON.'" alt="-" />
                    </span><u><b> '.$block->title.'</b></u></a>
                </div>'."\n".'<div id="vh_div'.$current_block.'">';

                /* checking each and every item under current root node */
                
                  foreach ($block->items as $key => $string) {
                    // creating a children node.
                    echo '<div class="depth1">';

                    // if item has a icon to display, then show it.
                    if ($block->icons) {
                        echo $block->icons[$key]."\n";
                    }

                    // indicates end of children node.
                    echo $string ."\n</div>\n";

                    $current_item++;

                  }  // end of each item node

                // close the depth2 division and make a space between this and next level.
                echo "</div>\n";

                if ($block->footer) {
                    echo '<div class="footer">'. $block->footer .'</div>';
                }

                if (!empty($THEME->customcorners)) {
                    echo '</div></div></div><div class="bb"><div>&nbsp;</div></div></div>';
                }

            }

        }

        print_tree_block_end($attributes, $title, true, $current_block);

        echo $skip_dest;

    }
}

/**
 * Prints the end of the tree block structure. Since, tree block requires different
 * type of content type (specially, javascripts) different methods has to be used.
 *
 * @Author Isuru Madushanka
 * @param  array $attributes important parameters identifying whoch block type is processing
 * @param  string $title Plain text title, as footer
 */
function print_tree_block_end($attributes = array(), $title='',$is_subblock = false, $no_of_div = 0, $collapse_fields = '') {
    global $CFG, $THEME, $USER;

    // Added by Isuru Madushanka
    // adds global variables indicating tree collapsed/expanded icon file names
    global $COLLAPSED_ICONFILE, $EXPANDED_ICONFILE;


    echo '</div>';
    if (!empty($THEME->customcorners)) {
        echo '</div></div></div><div class="bb"><div>&nbsp;</div></div></div>';
    }
    echo '</div>';

    $strshow = addslashes_js(get_string('showblocka', 'access', strip_tags($title)));
    $strhide = addslashes_js(get_string('hideblocka', 'access', strip_tags($title)));

    // IE workaround: if I do it THIS way, it works! WTF?
    if (!empty($CFG->allowuserblockhiding) && isset($attributes['id'])) {
        if (!$is_subblock) {
            echo '<script type="text/javascript">'."\n//<![CDATA[\n".'elementCookieHide("'.$attributes['id'].
                '","'.$strshow.'","'.$strhide."\");\n//]]>\n".'</script>';
        } else {
            /// prints the Javascript functions which are needed for controlling behaviour of tree when user clicked on an item.
            echo '<script type="text/javascript">'."\n//<![CDATA[\n
                        var vh_numdivs = ".$no_of_div.";
                        var parkplatz  = new Array();
                        for (var i=1; i<=vh_numdivs; i++) {
                            parkplatz[i] = null;
                        }

                        function menu_toggle(i) {
                            i = parseInt(i);
                            if (parkplatz[i] === null) {
                                collapse(i);
                            } else {
                                expand(i);
                            }
                        }

                        function collapse(i) {
                            if (parkplatz[i] !== null) {
                                return;
                            }
                            var obj = document.getElementById(\"vh_div\"+String(i));
                            if (obj === null) {
                                return;
                            }
                            var nothing = document.createElement(\"span\");
                            nothing.setAttribute(\"id\", \"vh_div\"+String(i));
                            parkplatz[i] = obj;
                            obj.parentNode.replaceChild(nothing, obj);
                            var icon = document.getElementById(\"vh_div\"+String(i)+\"indicator\");
                            icon.innerHTML = \"<img src=\\\"".$CFG->pixpath."/i/".EXPANDED_ICON."\\\" alt=\\\"+\\\" />\";
                        }

                        function expand(i) {
                            if (parkplatz[i] === null) {
                                return;
                            }
                            var nothing = document.getElementById(\"vh_div\"+String(i));
                            var obj = parkplatz[i];
                            parkplatz[i] = null;
                            nothing.parentNode.replaceChild(obj, nothing);
                            var icon = document.getElementById(\"vh_div\"+String(i)+\"indicator\");
                            icon.innerHTML = \"<img src=\\\"".$CFG->pixpath."/i/".COLLAPSED_ICON."\\\" alt=\\\"-\\\" />\";
                        }

                        function expandall() {
                            for (i=1; i<=vh_numdivs; i++) {
                                expand(i);
                            }
                        }

                        function collapseall() {
                            for (var i=vh_numdivs; i>0; i--) {
                                collapse(i);
                            }
                        }";

            // collapse all nodes.
            echo "collapseall();\n//]]>\n".'</script>';

        }

    }

}


?>
